package com.chinasofti.framework.dataaccess;

import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;


import com.chinasofti.framework.base.App;
import com.chinasofti.framework.data.Entity;
import com.chinasofti.framework.dataaccess.Condition.Operation;
import com.chinasofti.framework.dataaccess.Filter.Relation;

public class DataAccessUtils {
	public static <T extends Entity> void find(ArrayList<T> entities, 
			Filter filter, ArrayList<T> outEntities) {
		if(filter == null) {
			return;
		}
		Relation relation = filter.getRelation();
		if(relation == null) {
			relation = Relation.AND;
		}
		
		
		for(int i = 0; i < entities.size(); i++) {
			Entity entity = entities.get(i);
			if(relation.equals(Relation.AND)) {
				boolean res = true;
				for(int ii = 0; ii < filter.getConditions().size(); ii++) {
					Condition con = filter.getConditions().get(ii);
					String field = con.getField();
					Object toValue = con.get("Value");
					Operation conOpr = con.getOperation(); 
					if(!entity.compare(field, toValue, conOpr)){
						res = false;
						break;
					}
				}
				if(res) {
					outEntities.add(entities.get(i));
				}
			}
			else {
				boolean res = false;
				for(int ii = 0; ii < filter.getConditions().size(); ii++) {
					Condition con = filter.getConditions().get(ii);
					String field = con.getField();
					Object toValue = con.get("Value");
					Operation conOpr = con.getOperation(); 
					if(entity.compare(field, toValue, conOpr)) {
						res = true;
						break;
					}
				}
				if(res) {
					outEntities.add(entities.get(i));
				}
			}
		}
	}
	
	public static <T extends Entity> long getSqlLiteData(IReadDataAccess<T> dataAccess, 
			long from, long to, ArrayList<T> outEntities) throws Exception {
		T entity = dataAccess.createEntityInstance();
		String sql = "SELECT * FROM " + entity.getEntityName(); 
		
		Class.forName("org.sqlite.JDBC");
		String sqlPath = App.getInstance().getLocalDataBasePath();
		String url = "jdbc:sqlite" + sqlPath;
		Connection conn = DriverManager.getConnection(url);
		Statement statement = conn.createStatement();
		
		statement.execute(sql);
		ResultSet rs = statement.getResultSet();
		ArrayList<T> entities = new ArrayList<T>();
		long i = 0;
		
		while(rs.next() && i >= from && i < to) {
			T entity2 = dataAccess.createEntityInstance();
			setRow(rs, entity);
			entities.add(entity2);
			i++;
		}
		conn.close();	
		return 0;
	}
	
	public static <T extends Entity> ArrayList<T> getSqlLiteData(IReadDataAccess<T> dataAccess)
			throws Exception {
		T entity = dataAccess.createEntityInstance();
		String sql = "SELECT * FROM " + entity.getEntityName(); 
		
		Class.forName("org.sqlite.JDBC");
		String sqlPath = App.getInstance().getLocalDataBasePath();
		String url = "jdbc:sqlite" + sqlPath;
		Connection conn = DriverManager.getConnection(url);
		Statement statement = conn.createStatement();
		
		statement.execute(sql);
		
		ResultSet rs = statement.getResultSet();
		ArrayList<T> entities = new ArrayList<T>();
		while(rs.next()) {
			T entity2 = dataAccess.createEntityInstance();
			setRow(rs, entity);
			entities.add(entity2);
		}
		conn.close();		
		return entities;
	}
	
	public static <T extends Entity> T getSqlLiteData(Object key, 
			IReadDataAccess<T> dataAccess) throws Exception{
		T entity = dataAccess.createEntityInstance();
		String entityName = entity.getEntityName();
		String sql = "SELECT * FROM " + entityName 
			+ " WHERE " + entity.getKeyField() + "=" + key.toString();
		
		Class.forName("org.sqlite.JDBC");
		String sqlPath = App.getInstance().getLocalDataBasePath();
		String url = "jdbc:sqlite" + sqlPath;
		Connection conn = DriverManager.getConnection(url);
		Statement statement = conn.createStatement();
		statement.execute(sql);
		ResultSet rs = statement.getResultSet();
		if(rs.next()) {
			setRow(rs, entity);
		}
		return entity;
	}
	
	public static <T extends Entity> ArrayList<T> getSqlLiteData(Filter filter,
			IReadDataAccess<T> dataAccess) throws Exception{
		Class.forName("org.sqlite.JDBC");
		String sqlPath = App.getInstance().getLocalDataBasePath();
		String url = "jdbc:sqlite" + sqlPath;
		Connection conn = DriverManager.getConnection(url);
		Statement statement = conn.createStatement();
		String sql = filter.toSqlString();
		statement.execute(sql);
		ResultSet rs = statement.getResultSet();
		ArrayList<T> entities = new ArrayList<T>();
		while(rs.next()) {
			T entity = dataAccess.createEntityInstance();
			setRow(rs, entity);
			entities.add(entity);
		}
		conn.close();		
		return entities;
	}
	
	public static void setRow(ResultSet rs,  Entity entity) throws SQLException {
		List<String> nameList = entity.getFieldNameList();
		for(int i = 0; i < nameList.size(); i++) {
			String fieldName = nameList.get(i);
			String columnName = fieldName;
			Type columnType = entity.getFieldType(fieldName);
			if(columnType == Integer.class) {
				int value = rs.getInt(fieldName);
				entity.set(fieldName, value);
			}
			else if(columnType == Long.class) {
				long value = rs.getLong(columnName);
				entity.set(fieldName, value);
			}
			else if(columnType == Float.class) {
				float value = rs.getFloat(columnName);
				entity.set(fieldName, value);
			}
			else if(columnType == Double.class) {
				double value = rs.getDouble(columnName);
				entity.set(fieldName, value);
			}
			else if(columnType == Boolean.class) {
				boolean value = rs.getBoolean(columnName);
				entity.set(fieldName, value);
			}
			else if(columnType == Short.class) {
				short value = rs.getShort(columnName);
				entity.set(fieldName, value);
			}
			else if(columnType == String.class) {
				String value = rs.getString(columnName);
				entity.set(fieldName, value);
			}
			else if(columnType == Byte.class) {
				byte value = rs.getByte(columnName);
				entity.set(fieldName, value);
			}
		}
	}
	
	
}
